//
//  StatisticsServer.cpp
//  Simulation
//
//  Created by Christopher Kemsley on 3/7/12.
//  Copyright (c) 2012 iAppolopolis. All rights reserved.
//

#include "StatisticsServer.hpp"
#include "System.hpp"
#include <iostream>
#include "Log.hpp"

#include "Codec.hpp"
#include "Settings.hpp"



StatsNamespaceBegin

std::ostream&	operator<<	( std::ostream & stream , Node const & node )
	{
	Node::Map::const_iterator	end		=	node.mPeriods.end() ;
	Node::Map::const_iterator	idle	=	node.mPeriods.find(Node::kIdle) ;
	Node::Map::const_iterator	busy	=	node.mPeriods.find(Node::kBusy) ;
	Node::Map::const_iterator	error	=	node.mPeriods.find(Node::kErronious) ;
	
	stream << Server::shared().mName ;
	stream << "," ;
	stream << node.mName ;
	
	double	value ;
	
	if ( idle != end )
		{
		value	=	(*idle).second.secondsValue() ;
		if ( value == 0 )
			stream	<< ",0" ;
		else
			stream	<< "," << value ;
		}
	else
		{
		stream	<< ",0" ;
		}
	
	if ( busy != end )
		{
		value	=	(*busy).second.secondsValue() ;
		if ( value == 0 )
			stream	<< ",0" ;
		else
			stream	<< "," << value ;
		}
	else
		{
		stream	<< ",0" ;
		}
	
	if ( error != end )
		{
		value	=	(*error).second.secondsValue() ;
		if ( value == 0 )
			stream	<< ",0" ;
		else
			stream	<< "," << value ;
		}
	else
		{
		stream	<< ",0" ;
		}
	
	//stream << "	" << (*idle).second << "	" << (*busy).second << "	" << (*error).second ;
	
	return stream ;
	}

StatsNamespaceEnd




using namespace Statistics ;
using Sim::Interval ;

using namespace Sim ;




struct ServerSettings : public Sim::Settings
{
	Sim::URL	logURL ;
	std::string	testName ;
	
	ServerSettings ()
	:	Sim::Settings("Statistics")
	,	logURL ( "./statistics.csv" )
		{
		add ( "logURL" , logURL ) ;
		add ( "testName" , testName ) ;
		}
} ;


void	Server :: loadConfiguration	( Sim::URL url )
	{
	ServerSettings	settings ;
	Codec :: decode<URL,Settings> ( url , settings ) ;
	
	std::string	path	=	settings.logURL.absolutePath() ;
	Server::shared().mStream . open ( path.c_str() , std::ios_base::out ) ;
	if ( ! Server::shared().mStream.is_open() )
		ThrowException ( "Statistics" , "Failed to open log file for writing" , __FILE__,__LINE__ ) ;
	
	Server::shared().mName = settings.testName ;
	}

Server&	Server :: shared ()
	{
	static Server s ;
	return s ;
	}
Server :: Server ()
:	mStream ()
	{
	
	}
Server :: ~Server ()
	{
	mStream.close() ;
	}


void	Server :: logNode	( Node const & node )
	{
	mStream << node << "\n" ;
	}









Node :: Node	( std::string const & name )
:	mName	( name )
,	mRegion	( kIdle )
,	mTime	( Sim::System::shared().currentTime() )
,	mPeriods()
	{
	
	}
Node :: ~Node	()
	{
	(*this) << kIdle ;
	Log::output() << "\n" << (*this) ;
	Server::shared() . logNode ( *this ) ;
	}

void	Node :: operator<<	( Region const & region )
	{
	Region	r	=	mRegion ;
	if ( ( region & kRetroactive ) != 0 )
		{
		r = region & (~kRetroactive) ;
		}
	
	Sim::Log::states("Statistics::Node") << mName << " = " << regionTitle(region) << " ("<<regionTitle(r)<<")" ;
	
	Interval	now		=	Sim::System::shared().currentTime() ;
	Interval	diff	=	now - mTime ;
	mTime				=	now ;
	mRegion				=	region ;
	
	mPeriods [r]		+=	diff ;
	}

std::string const	Node :: regionTitle ( Region const & region )
	{
	std::string		returner ;
	
	if ( ( region & 3 ) == kIdle )
		returner = "Idle" ;
	else if ( ( region & 3 ) == kBusy )
		returner = "Busy" ;
	else if ( ( region & 3 ) == kErronious )
		returner = "Erronious" ;
	
	if ( region & kRetroactive )
		returner += " (retroactive)" ;
	
	return returner ;
	}
